package com.stxx.stiot2.event.task;

import com.stxx.framwork.constants.AlarmPolicyType;
import com.stxx.stiot2.constants.RedisKeys;
import com.stxx.stiot2.domain.Alarm;
import com.stxx.stiot2.domain.Scene;
import com.stxx.stiot2.domain.ext.AlarmPlan;
import com.stxx.stiot2.domain.ext.AlarmState;
import com.stxx.stiot2.domain.ext.Period;
import com.stxx.stiot2.event.dto.T2pMsg;
import com.stxx.stiot2.utils.ServerUtils;
import lombok.Data;
import org.noear.solon.Solon;
import org.noear.solon.core.handle.Context;
import org.noear.solon.expression.snel.SnEL;

import java.sql.SQLException;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.Executor;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.time.LocalDate;


public class SceneTask implements Runnable{
    private final static Pattern p = Pattern.compile("#\\{(\\w+)\\}");
    private Scene scene;
    private T2pMsg message;
    public SceneTask(Scene scene, T2pMsg message) {
        this.scene = scene;
        this.message = message;
    }
    @Override
    public void run() {
        if(!isWorkTime())return;
        SnParams snParams = getSnParams(scene.getTriggerExpress());
        if(snParams == null)return;
        //报警触发，执行联动
        boolean trigger = false;
        try{
            trigger = (boolean)SnEL.eval(snParams.getExpress(),snParams.getContext());
        }catch (Exception ex){

        }
        if(scene.getAlarmEnable()){
            alarm(trigger);
        }
        if(scene.getActionEnable()) {
            actionExec(trigger);
        }
    }

    /**
     * 处理报警逻辑
     * @param trigger
     */
    private void alarm(Boolean trigger) {
        AlarmState alarmState = ServerUtils.getRedisServer().getObj(getRedisKey(), AlarmState.class);
        //不触发告警且当前设备不告警时
        Executor executor = Solon.context().getBean(Executor.class);
        if(trigger) {
            if(alarmState==null) {
                alarmState = new AlarmState();
                alarmState.setId(UUID.randomUUID().toString().replace("-",""));
                alarmState.setAlarmCount(1);
                alarmState.setAlarmTs(System.currentTimeMillis());
            }else{
                alarmState.setAlarmCount(alarmState.getAlarmCount()+1);
            }
            alarmState.setClearCount(0);
            alarmState.setClearTs(0);
            if(alarmState.isAlarming()) {
                //获取报警消息
                Alarm alarm = ServerUtils.getAlarmService().queryById(alarmState.getId());
                if (alarm == null) return;
                alarm.setEndTime(LocalDateTime.now());
                alarm.setAdditionalInfo(getAlarmMessage());
                try {
                    ServerUtils.getAlarmService().update(alarm);
                    executor.execute(new SubscribeAlarmTask(alarm,"update"));
                } catch (SQLException e) {
                    throw new RuntimeException(e);
                }
            }else{
                //如果没有报警，计算是否可以报警
                boolean canAlarm = false;
                if (scene.getAlarmSetting().getTriggerMode() == AlarmPolicyType.CONTINUOS) {
                    canAlarm = alarmState.getAlarmCount() >= scene.getAlarmSetting().getClearValue();
                } else {
                    canAlarm = (System.currentTimeMillis() - alarmState.getAlarmTs()) / 1000 >= scene.getAlarmSetting().getClearValue();
                }
                if (canAlarm) {
                    alarmState.setAlarming(true);
                    Alarm alarm = new Alarm();
                    alarm.setId(alarmState.getId());
                    alarm.setTerminalCode(message.getTerminalCode());
                    alarm.setName(scene.getName());
                    alarm.setCleared(false);
                    alarm.setConfirmed(false);
                    alarm.setStartTime(LocalDateTime.now());
                    alarm.setEndTime(LocalDateTime.now());
                    alarm.setAdditionalInfo(getAlarmMessage());
                    try {
                        ServerUtils.getAlarmService().insert(alarm);
                        executor.execute(new SubscribeAlarmTask(alarm,"create"));
                    } catch (SQLException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
            //保存状态
            ServerUtils.getRedisServer().setObj(getRedisKey(), alarmState);
        }else if(scene.getAlarmSetting().getAutoClear()
                &&alarmState!=null
                &&alarmState.isAlarming()){
            SnParams snParams = getSnParams(scene.getAlarmSetting().getClearExpress());
            boolean clearExpress = snParams != null&&(boolean)SnEL.eval(snParams.getExpress(),snParams.getContext());
            if(clearExpress) {
                alarmState.setClearCount(alarmState.getClearCount() + 1);
                if (alarmState.getClearTs() == 0) alarmState.setClearTs(System.currentTimeMillis());
                boolean canClear = false;
                if(scene.getAlarmSetting().getClearMode()==AlarmPolicyType.CONTINUOS){
                    canClear = alarmState.getClearCount()>=scene.getAlarmSetting().getClearValue();
                }else{
                    canClear = (System.currentTimeMillis() - alarmState.getClearTs())/1000 >= scene.getAlarmSetting().getClearValue();
                }
                if(canClear) {
                    ServerUtils.getRedisServer().delete(getRedisKey());
                    //如果报警状态不为空，且正在报警，且表达式为true，且满足清除条件 时，清除报警
                    Alarm alarm = ServerUtils.getAlarmService().queryById(alarmState.getId());
                    if(alarm!=null) {
                        alarm.setCleared(true);
                        alarm.setClearTime(LocalDateTime.now());
                        alarm.setEndTime(LocalDateTime.now());
                        try {
                            ServerUtils.getAlarmService().update(alarm);
                            executor.execute(new SubscribeAlarmTask(alarm,"clear"));
                        } catch (SQLException e) {
                            throw new RuntimeException(e);
                        }
                    }
                }else{
                    //保存状态
                    ServerUtils.getRedisServer().setObj(getRedisKey(), alarmState);
                }
            }

        }

    }

    /**
     * 处理联动逻辑
     * @param trigger
     */
    private void actionExec(Boolean trigger) {
        if(!trigger)return;
        scene.getActionFlow().forEach(actionFlow->{
            ServerUtils.getExecutor().execute(new ActionFlowTask(scene.getId(), actionFlow.getActions(),message));
        });
    }


    private String getRedisKey(){
        return RedisKeys.terminal_alarm+message.getTerminalCode()+":"+scene.getName();
    }




    private boolean isWorkTime(){
        if(!scene.getPlanEnable()) {
            return true;
        }
        LocalDate today = LocalDate.now(); // 获取当前日期
        final int weekIndex = today.getDayOfWeek().getValue()-1;
        for(AlarmPlan week : scene.getPlan()){
            if(week.getId()==weekIndex){
                for (Period item : week.getValues()){
                    LocalTime now = LocalTime.now();
                    LocalTime start = LocalTime.parse(item.getS());
                    LocalTime end = LocalTime.parse(item.getE());
                    if(now.isAfter(start)&&(now.isBefore(end)||end.equals(LocalTime.of(0,0)))){
                        return true;
                    }
                }
            }
        }
        return false;
    }

    public SnParams getSnParams(String express) {
        if(express==null)return null;
        Map<String,Object> context = new HashMap<String,Object>();
        StringBuffer sb = new StringBuffer();
        Matcher m = p.matcher(express);
        while(m.find()){
            String key = m.group(1);
            if(!message.getData().getProperties().containsKey(key)){
                return null;
            }
            context.put(key,message.getData().getProperties().get(key));
            m.appendReplacement(sb,m.group(1));
        }
        m.appendTail(sb);
        SnParams snParams = new SnParams();
        snParams.setContext(context);
        snParams.setExpress(sb.toString());
        return snParams;
    }

    public String getAlarmMessage() {
        if(scene.getAlarmSetting().getDetail()==null)return null;
        Map<String,Object> context = new HashMap<String,Object>();
        Matcher m = p.matcher(scene.getAlarmSetting().getDetail());
        while(m.find()){
            String key = m.group(1);
            if(!message.getData().getProperties().containsKey(key)){
                context.put(key,ServerUtils.getTerminalService().getLastValue(message.getTerminalCode(),key).toString());
            }else{
                context.put(key,message.getData().getProperties().get(key).toString());
            }
        }
        //context.properties(Solon.cfg()); //绑定应用属性，支持 ${表过式}
        return SnEL.evalTmpl(scene.getAlarmSetting().getDetail(),context);
    }

    @Data
    public static class SnParams{
        String express;
        Map<String,Object> context;
    }

    public static void main(String[] args) {
        Map<String,Object> ddd = new HashMap<>();
        ddd.put("a",10);
        String b= SnEL.evalTmpl("${a} is ok",ddd);
        System.out.println(b);
    }

}
